// eee.Sheffield.PZ.Imaging
//
// Copyright ?Ping Zou, 2006
// sg71.cherub@gmail.com
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace eee.Sheffield.PZ.Imaging
{
    /// <summary>
    /// Image class
    /// </summary>
    public class Image
    {
        /// <summary>
        /// standarize image into 24RGB
        /// </summary>
        /// <param name="src"></param>
        public static void StandardizeImageTo24bppRGB(ref Bitmap srcImage)
        {
            int width = srcImage.Width;
            int height = srcImage.Height;

            // standarize srcImage to 24RGB
            if (srcImage.PixelFormat != PixelFormat.Format24bppRgb)
            {
                Bitmap temp1 = srcImage;                
                Rectangle rect = new Rectangle(0, 0, width, height);
                srcImage = (Bitmap)temp1.Clone(rect, PixelFormat.Format24bppRgb);
                temp1.Dispose();               
            }
        } // StandardizeImageTo24bppRGB()

        public static void StandardizeImageTo8bbpIndexed(ref Bitmap srcImage)
        {
            int width = srcImage.Width;
            int height = srcImage.Height;

            // standarize srcImage to 8bbprgb
            if (srcImage.PixelFormat != PixelFormat.Format8bppIndexed)
            {

                if (srcImage.PixelFormat == PixelFormat.Format24bppRgb)
                {
                    BitmapData srcImageData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    int srcOffset = srcImageData.Stride - 3 * width;

                    Bitmap newImage = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
                    BitmapData newImageData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
                    int newOffset = newImageData.Stride - width;
                    unsafe
                    {
                        byte* src = (byte*)srcImageData.Scan0.ToPointer();
                        byte* newp = (byte*)newImageData.Scan0.ToPointer();

                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++, src += 3, newp++)
                            {
                                *newp = *src;
                            }
                            src += srcOffset;
                            newp += newOffset;
                        }
                    }
                    srcImage.UnlockBits(srcImageData);
                    newImage.UnlockBits(newImageData);

                    //newImage.Save("newimage.bmp", ImageFormat.Bmp);
                    //srcImage.Save("srcimage.bmp", ImageFormat.Bmp);

                    Bitmap temp = srcImage;
                    srcImage = (Bitmap)newImage.Clone();
                    temp.Dispose();
                }
                else if (srcImage.PixelFormat == PixelFormat.Format32bppArgb)
                {
                    BitmapData srcImageData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    int srcOffset = srcImageData.Stride - 4 * width;

                    Bitmap newImage = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
                    BitmapData newImageData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
                    int newOffset = newImageData.Stride - width;
                    unsafe
                    {
                        byte* src = (byte*)srcImageData.Scan0.ToPointer();
                        byte* newp = (byte*)newImageData.Scan0.ToPointer();

                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++, src += 4, newp++)
                            {
                                *newp = *(src + 1);
                            }
                            src += srcOffset;
                            newp += newOffset;
                        }
                    }
                    srcImage.UnlockBits(srcImageData);
                    newImage.UnlockBits(newImageData);

                    //newImage.Save("newimage.bmp", ImageFormat.Bmp);
                    //srcImage.Save("srcimage.bmp", ImageFormat.Bmp);

                    Bitmap temp = srcImage;
                    srcImage = (Bitmap)newImage.Clone();
                    temp.Dispose();
                }
                else
                    throw new ApplicationException("Image;:StandardizeImageTo8bbpIndexed(), source image is not RGB.");
            }

            // set pallete of the image to grayscale
            GenerateGraylevelPalette(ref srcImage);

        } // StandardizeImageTo8bbpIndexed()    

        public static void GenerateGraylevelPalette(ref Bitmap srcImage)
        {
            if (srcImage.PixelFormat != PixelFormat.Format8bppIndexed)
                throw new ApplicationException("Image::GenerateGraylevelPalette(), source image is not in Format8bppIndexed");
            // init graylevel palette
            {
                ColorPalette cp = srcImage.Palette;
                // init palette
                for (int i = 0; i < 256; i++)
                    cp.Entries[i] = Color.FromArgb(i, i, i);
                // set palette back
                srcImage.Palette = cp;
            }
        } // GenerateGraylevelPalette()

        public static bool IsGraylevelImage(Bitmap srcImage)
        {
            bool isGraylevelImage = true;
            if (srcImage.PixelFormat != PixelFormat.Format8bppIndexed)
                //return isGraylevelImage;
            //else
            {
                if (srcImage.PixelFormat == PixelFormat.Format24bppRgb)
                {
                    int height = srcImage.Height;
                    int width = srcImage.Width;
                    BitmapData srcImageData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    int srcOffset = srcImageData.Stride - 3 * width;
                    unsafe
                    {
                        byte* src = (byte*)srcImageData.Scan0.ToPointer();
                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++, src += 3)
                            {
                                if ((*src != *(src + 1)) || (*(src + 1) != *(src + 2)) || (*(src + 2) != *src))
                                {
                                    isGraylevelImage = false;
                                    break;
                                }
                            }
                            src += srcOffset;
                        }
                    }
                    srcImage.UnlockBits(srcImageData);
                    //return isGraylevelImage;
                }
                else
                {
                    isGraylevelImage = false;
                    throw new ApplicationException("Image::IsGraylevelImage(), source image is not Format8bppIndexed nor Format24bppRGB.");                    
                }
            }
            return isGraylevelImage;
        } // IsGraylevelImage

        public static bool IsBlackAndWhite(Bitmap srcImage)
        {
            bool isBlackAndWhite = true;
            int width = srcImage.Width;
            int height = srcImage.Height;
            if (srcImage.PixelFormat == PixelFormat.Format24bppRgb)
            {
                BitmapData srcImageData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                int srcOffset = srcImageData.Stride - 3 * width;
                unsafe
                {
                    byte* src = (byte*)srcImageData.Scan0.ToPointer();
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++, src += 3)
                        {
                            if (!((*src == 255 && *(src + 1) == 255 && *(src + 2) == 255)
                                || (*src == 0 && *(src + 1) == 0 && *(src + 2) == 0)))
                            {
                                isBlackAndWhite = false;
                                break;
                            }
                        }
                        src += srcOffset;
                    }
                }
                srcImage.UnlockBits(srcImageData);
                //return isBlackAndWhite;
            }
            else if (srcImage.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                BitmapData srcImageData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
                int srcOffset = srcImageData.Stride - width;
                unsafe
                {
                    byte* src = (byte*)srcImageData.Scan0.ToPointer();
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++, src ++)
                        {
                            if (!((*src == 255)
                                || (*src == 0)))
                            {
                                isBlackAndWhite = false;
                                break;
                            }
                        }
                        src += srcOffset;
                    }
                }
                srcImage.UnlockBits(srcImageData);
                //return isBlackAndWhite;
            }
            else
            {
                isBlackAndWhite = false;
                throw new ApplicationException("Image::IsBlackAndWhite(), source image is not Format24bppRGB nor Format8bppIndexed.");                
            }
            return isBlackAndWhite;
        } // IsBlackAndWhite()
    }
}
